// JobExecuter.cpp: implementation of the CJobExecuter class.
//Author : Pradeep K Sahu
//Email : sahupk@yahoo.com
//Note   : You are free to use the code, and modify. Provided you
//         don't remove this comments. It will be great if you can provide
//		   your feedback.
//////////////////////////////////////////////////////////////////////

#include "stdafx.h"
#include "JobQ.h"
#include "JobExecuter.h"

#ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[]=__FILE__;
#define new DEBUG_NEW
#endif

#define STOP_WORKING -1
#define KEEP_WORKING  0

CJobExecuter::CJobExecuter(CMThreadedJobQ *pJobQ)
{
	this->m_pJobQ= pJobQ;
	this->m_pExecuterThread= AfxBeginThread(ThreadFunction,this);
	this->m_pJob2Do = NULL;
	this->m_flag = KEEP_WORKING;
}

CJobExecuter::~CJobExecuter()
{
	//The lines below are added later to solve the memory leak.
	//The leaks are found and solved by "Guitool" having member no Member No. 7253 
	if(this->m_pExecuterThread!= NULL )	
	{
		this->m_pExecuterThread->ExitInstance();
		delete m_pExecuterThread;	
	}
	//End of code suggested by "Guitool".
}

UINT CJobExecuter::ThreadFunction(LPVOID pParam)
{
	
	CJobExecuter *pExecuter = (CJobExecuter *)pParam;
	pExecuter->m_flag = 1;
	::Sleep(1);
	CSingleLock singleLock(&pExecuter->m_pJobQ->m_cs);		
	while(pExecuter->m_flag !=STOP_WORKING )
	{
		if(pExecuter->m_pJob2Do!=  NULL)
		{
			pExecuter->m_pJob2Do->execute();
			pExecuter->m_pJob2Do->m_Completed = TRUE;	
			if(pExecuter->m_pJob2Do->AutoDelete())
				delete pExecuter->m_pJob2Do;
			pExecuter->m_pJob2Do = NULL;
		}
		//If the JobQ is NULL then break
		if(pExecuter->m_pJobQ == NULL) break;
		
		//If the number of threads are more than the limit then end this executer
		CSingleLock singleLock(&pExecuter->m_pJobQ->m_cs);		
		singleLock.Lock();
		if(pExecuter->m_pJobQ->getNoOfExecuter() > pExecuter->m_pJobQ->getMaxNoOfExecuter())
		{
			pExecuter->stop();	
			singleLock.Unlock();	
		}
		else
		{
			//Add the Executer to the Executerpool of Job Q
			pExecuter->m_pJobQ->addFreeJobExecuter(pExecuter);
			singleLock.Unlock();	
			//Resume the Observer of so that new Job can be assigned if present in the Q
			pExecuter->m_pJobQ->m_pObserverThread->ResumeThread();		
			//suspend this thread
			pExecuter->m_pExecuterThread->SuspendThread();		
		}				
	}
	// Now If the Delete the thread from the FreeExecuterList of JobQ.
	if(pExecuter->m_pJobQ != NULL)
	{
		pExecuter->m_pJobQ->deleteJobExecuter(pExecuter);

	}
	else
	{
		delete pExecuter;
	}

	return 0;
}

void CJobExecuter::execute(CJob* pJob)
{
	this->m_pJob2Do = pJob;
	//Now the thread should be resumed to process the Job
	::Sleep(0);
	this->m_pExecuterThread->ResumeThread();
}

void CJobExecuter::stop()
{
	this->m_flag = STOP_WORKING;
	this->m_pExecuterThread->ResumeThread();
}
